home *** CD-ROM | disk | FTP | other *** search
- { Demonstrates formatting a floppy disk from Turbo Pascal.
- This version only formats DSDD 9 sector floppies (360KB).
- Works with DOS 2.0 or 3.0 in either 360K or 1.2M drives.
- Does not support a /S option.
- Supports a /N or -N option that turns off the verify after format.
- Turn off verify step and obtain a 2x speedup vs. DOS format.
-
- Requires Turbo version 3.0 to compile. Compile with Minheap=Maxheap=$200.
- Requires a cloning procedure after being compiled to a .COM file.
- The cloning procedure copies the boot sector of an already-formatted
- floppy into the program, where it can be used thereafter. To clone,
- call the program as follows:
-
- FMAT @ <enter>
-
- Written 10/26/85. Kim Kokkonen, TurboPower Software.
- Compuserve 72457,2131. (408)-378-3672. }
-
- PROGRAM Fmat;
- TYPE
- SectorBuffer = ARRAY[1..512] OF Char; { holds sector data during sector setup after formatting }
- FakeSectorBuffer = RECORD { same size as sector Buffer but easily initialized in code segment }
- L, H : STRING[255]
- END;
- FormatRecord = RECORD
- Cyl, Hed, Rec, Num : Byte
- END;
- FormatArray = ARRAY[1..18] OF FormatRecord;
- DiskBaseRec = RECORD
- Unk1, Unk2, Mtr, Bps, Eot, Gpl, Dtl, Glf, Fbf, Hst, Mst : Byte
- END;
- DiskBasePtr = ^DiskBaseRec;
- Registers = RECORD
- CASE Integer OF
- 1 : (AX, BX, CX, DX, BP, SI, DI, DS, ES, Flags : Integer);
- 2 : (AL, AH, BL, BH, CL, CH, DL, DH : Byte)
- END;
- FATtable = ARRAY[0..1023] OF Byte;
-
- CONST
- { bootrecord is customized after the .COM file is created.
- call FMAT with a single command line parameter '@' as follows:
- FMAT @ <Enter>. This will fill in bootrecord with a real boot record }
- BootRecord : FakeSectorBuffer = { fill in with bootrecord } (l : ''; H : '');
-
- VAR
- Reg : Registers;
- SB : SectorBuffer; { will fill in with dir sectors }
- BR : SectorBuffer ABSOLUTE BootRecord;
- VB : ARRAY[1..9] OF SectorBuffer; { will use for fast verify }
- FMT : FormatArray;
- FAT : FATtable;
- DrName : STRING[2];
- Param : STRING[10];
- Drive, D_Type : Byte;
- Ch : Char;
- DoVerify : Boolean;
- BiosDiskBase : DiskBasePtr ABSOLUTE 0 : $78;
- OldDiskBase : DiskBasePtr;
- I, Error : Integer;
- T_Avail : Integer;
- B_Avail : Real;
-
- PROCEDURE BiosReadSectors (Funct, Drive : Byte;
- Sector, Track, Head : Integer;
- Sects : Integer;
- VAR Buffer;
- VAR Error : Integer);
- { -execute int 13 to read disk or verify via BIOS at low level }
- BEGIN
- Reg.AX := (Funct Shl 8) OR Sects;
- Reg.DL := Drive;
- Reg.DH := Head;
- Reg.CH := Track AND 255;
- Reg.CL := (Sector AND 63) OR ((Track Shr 8) Shl 6);
- Reg.ES := Seg (Buffer);
- Reg.BX := Ofs (Buffer);
- Intr ($13, Reg);
- IF Odd (Reg.Flags AND 1) THEN
- Error := Reg.AX Shr 8
- ELSE
- Error := 0
- END; { BiosReadSectors }
-
- PROCEDURE BIOS_WriteSectors (Drive : Byte;
- Sector, Track, Head : Integer;
- Sects : Integer;
- VAR Buffer : SectorBuffer;
- VAR Error : Integer);
- { -execute int 13 to write disk via BIOS at low level }
- BEGIN
- Reg.AX := $300 OR Sects;
- Reg.DL := Drive;
- Reg.DH := Head;
- Reg.CH := Track AND 255;
- Reg.CL := (Sector AND 63) OR ((Track Shr 8) Shl 6);
- Reg.ES := Seg (Buffer);
- Reg.BX := Ofs (Buffer);
- Intr ($13, Reg);
- IF Odd (Reg.Flags AND 1) THEN
- BEGIN
- Error := Reg.AX Shr 8;
- WriteLn ('Error during format...');
- Halt;
- END
- ELSE
- Error := 0
- END; { BIOS_WriteSectors }
-
- PROCEDURE InitBoot;
- { -self-customize this program to hold the boot record }
- VAR
- Ch : Char;
- Error : Integer;
- F : FILE;
- Tries : Byte;
-
- FUNCTION CodeSize : Integer; { thanks to B. Tolz and R. Forgaard for this function }
- VAR
- I : Byte;
- BEGIN
- I := 11;
- WHILE NOT ((Mem[DSeg - 2:I+3] <> $00E9) AND
- (MemW[DSeg - 2:I+4] = $0000)) AND
- NOT ((MemW[DSeg - 2:I+0] = $00E9) AND
- (MemW[DSeg - 2:I+2] = $E800)) DO
- I := I+1;
- CodeSize := ((((DSeg - 2) - CSeg) Shl 4) + I + 6) - $100
- END; { CodeSize }
-
- BEGIN
- WriteLn ('You will now clone a copy of the boot record into this program...');
- WriteLn ('The completed version will be written to FMAT.COM');
- Write ('Place a DOS formatted disk in Drive A: and press any key when ready ');
- Read (KBD, Ch);
- WriteLn;
- Tries := 0;
- REPEAT { read the boot record }
- Tries := Succ (Tries);
- BiosReadSectors (2, 0, 1, 0, 0, 1, BR, Error);
- UNTIL (Error = 0) OR (Tries = 3);
- IF Error <> 0 THEN
- BEGIN
- WriteLn ('Could not read boot record.');
- Halt
- END;
- Assign (F, 'FMAT.COM'); { clone this program }
- Rewrite (F, 1);
- BlockWrite (F, Mem[CSeg : $100], CodeSize);
- Close (F);
- Halt
- END; { InitBoot }
-
- FUNCTION DOS_Version : Byte; { -return the major version number of DOS }
- BEGIN
- Reg.AH := $30;
- MsDos (Reg);
- DOS_Version := Reg.AL
- END; { DOS_Version }
-
- FUNCTION ATmachine : Boolean; { -return true if machine is AT class }
- VAR
- MachType : Byte ABSOLUTE $FFFF:$000E;
- BEGIN
- ATmachine := (MachType = $FC)
- END; { ATmachine }
-
- PROCEDURE ReadDASD (Drive : Byte; VAR D_Type : Byte); { -read dasd for DOS 3 }
- BEGIN
- Reg.AH := $15;
- Reg.DL := Drive;
- Intr ($13, Reg);
- IF Odd (Reg.Flags AND 1) THEN
- BEGIN
- WriteLn ('Error reading DASD for format...');
- Halt
- END;
- D_Type := Reg.AH
- END; { ReadDASD }
-
- PROCEDURE SetDASD (Drive, D_Type : Byte); { -execute int 13 to "set DASD" for format of 360K disks on 1.2MB floppies }
- VAR
- Tries : Byte;
- BEGIN
- Tries := 0;
- REPEAT
- Tries := Succ (Tries);
- Reg.AH := $17;
- Reg.AL := D_Type;
- Reg.DL := Drive;
- Intr($13, Reg);
- UNTIL (Tries = 3) OR NOT (Odd (Reg.Flags AND 1));
- IF Odd (Reg.Flags AND 1) THEN
- BEGIN
- WriteLn ('Error setting DASD for format...');
- Halt
- END
- END; { SetDASD }
-
- PROCEDURE Init_FAT; { -initialize a FAT sector }
- BEGIN { fill fat with all zeros }
- FillChar (FAT, 1024, 0); { fill in the ID Bytes }
- FAT[0] := $FD; { 9 sector DSDD Drive }
- FAT[1] := $FF; { boilerplate }
- FAT[2] := $FF;
- T_Avail := 80
- END; { Init_FAT }
-
- PROCEDURE InitDiskBase; { -modify the disk base data per DOS 3 instructions }
- BEGIN
- OldDiskBase := BiosDiskBase; { save old pointer }
- New (BiosDiskBase); { make a new disk base data area }
- BiosDiskBase^ := OldDiskBase^; { put the data from the old area in the new one }
- BiosDiskBase^.Glf := $50; { modify per dos 3 instructions, doesn'T hurt on DOS 2 }
- BiosDiskBase^.Eot := 9;
- END { InitDiskBase } ;
-
- PROCEDURE Format (Drive : Byte; VAR FMT : FormatArray; VAR Error : Integer);
- VAR
- I : Integer;
- BEGIN
- FOR I := 1 TO 9 DO { initialize format table }
- WITH FMT[I] DO
- BEGIN
- Cyl := 0; { cylinder number, will fill in during format }
- Hed := 0; { Head number }
- Rec := I; { sector number }
- Num := 2 { indicates 512 bytes per sector }
- END;
- FOR I := 1 TO 9 DO
- WITH FMT[I+9] DO
- BEGIN
- Cyl := 0; { cylinder number, will fill in during format }
- Hed := 1; { Head number }
- Rec := I; { sector number }
- Num := 2 { indicates 512 bytes per sector }
- END;
- { write the format information }
- InLine ($8A/$56/$0C/ { MOV DL,[BP+0C] - get Drive number }
- $C4/$5E/$08/ { LES BX,[BP+08] - get pointer to format array }
- $B9/$01/$00/ { MOV CX,0001 - track 0 sector 1 }
- { nexttrack: - loop over 40 disk tracks }
- $8B/$FB/ { MOV DI,BX - index into format array }
- $B0/$12/ { MOV AL,12 - number of sectors per track = 18 }
- { inittrack: - loop over 18 sectors per track }
- $26/$88/$2D/ { MOV ES:[DI],CH - track track number in format array }
- $81/$C7/$04/$00/ { ADD DI,0004 }
- $FE/$C8/ { DEC AL }
- $75/$F5/ { JNZ inittrack }
- $B6/$00/ { MOV DH,00 - format 9 sectors on side 0 }
- $B8/$01/$05/ { MOV AX,0501 }
- $CD/$13/ { INT 13 }
- $72/$18/ { JB Error - check for errors }
- $B6/$01/ { MOV DH,01 - format 9 sectors on side 1 }
- $B8/$01/$05/ { MOV AX,0501 }
- $53/ { PUSH BX }
- $81/$C3/$24/$00/ { ADD BX,0024 }
- $CD/$13/ { INT 13 }
- $72/$0A/ { JB Error - check for errors }
- $5B/ { POP BX }
- $FE/$C5/ { INC CH - next track }
- $80/$FD/$28/ { CMP CH,28 }
- $75/$D2/ { JNZ nexttrack }
- $31/$C0/ { XOR AX,AX - no errors, return 0 }
- { Error: }
- $C4/$7E/$04/ { LES DI,[BP+04] }
- $26/$89/$05); { MOV ES:[DI],AX - return Error code }
- END; { Format }
-
- PROCEDURE Verify (Drive : Byte; VAR FAT : FATtable; VAR Error : Integer);
- VAR
- T, H : Integer;
- Cluster, FAT_Ofs, TopCluster, Content : Integer;
- BEGIN { initialize the verify Buffer - 9 sectors * 512 bytes }
- FillChar (VB, 4608, $F6);
- FOR T := 0 TO 39 DO { verify all sectors }
- FOR H := 0 TO 1 DO
- BEGIN
- BiosReadSectors (4, Drive, 1, T, H, 9, VB, Error);
- IF Error <> 0 THEN
- BEGIN { mark the clusters on this track as unavailable }
- Cluster := ((9 * (H + 2 * T)) DIV 2) - 4;
- TopCluster := Cluster + 5;
- WHILE Cluster < TopCluster DO
- BEGIN
- FAT_Ofs := (3 * Cluster) DIV 2;
- Move (FAT[FAT_Ofs], Content, 2); { get a word from the FAT }
- IF Odd (Cluster) THEN { replace 12 bits of the word }
- Content := Content OR $FF70
- ELSE
- Content := Content OR $0FF7;
- Move (Content, FAT[FAT_Ofs], 2); { store it back }
- Cluster := Succ (Cluster)
- END;
-
- T_Avail := Pred (T_Avail) { reduce the number of tracks available }
- END
- END
- END; { Verify }
-
- PROCEDURE Init_DIR; { -initialize a sector for the root directory }
- VAR
- I : Integer;
- BEGIN
- FillChar (SB, 512, $F6); { fill with format bytes }
- FOR I := 1 TO 481 DO { mark each directory entry as available }
- IF ((I - 1) MOD 32) = 0 THEN
- SB[I] := #0
- END; { Init_DIR }
-
- BEGIN
- DoVerify := True;
- IF ParamCount = 0 THEN { get the Drive and DoVerify option }
- BEGIN
- Write ('Enter Drive to format: ');
- ReadLn (DrName)
- END
- ELSE { read the command line parameters }
- BEGIN
- I := 1;
- DrName := '';
- WHILE I <= ParamCount DO
- BEGIN
- Param := ParamStr (I);
- CASE Param[1] OF
- '@' : InitBoot; { clone the boot record into this program }
- '-', '/' : IF (Length (Param) = 2) AND (UpCase (Param[2]) = 'N') THEN
- DoVerify := False
- ELSE
- WriteLn ('WARNING: unrecognized command line option ', Param)
- ELSE
- DrName := Param
- END;
- I := Succ (I)
- END
- END;
- IF BR[1] = #0 THEN { make sure the bootrecord has been cloned into program }
- BEGIN
- WriteLn ('You must first clone a copy of the boot record');
- WriteLn ('into this program. Call as FMAT @ <Enter> to clone...');
- Halt
- END;
- IF (DrName = '') OR NOT (UpCase (DrName[1]) IN ['A', 'B']) THEN
- BEGIN { check for errors, should use DOS facilities to check non-removables }
- WriteLn ('Drive not Specified or cannot be formatted');
- Halt
- END;
- REPEAT { get BIOS Drive number }
- Drive := Ord (UpCase (DrName[1])) - 65;
- Write ('Insert new disk in Drive ', Chr (65 + Drive));
- Write (' and press <Enter> to begin formatting ');
- REPEAT
- Read (KBD, Ch)
- UNTIL (Ch = ^M);
- WriteLn;
- IF ATmachine AND (DOS_Version = 3) THEN
- BEGIN { get the Drive type, necessary when dealing with 1.2MB drives }
- ReadDASD (Drive, D_Type);
- IF (D_Type = 0) OR (D_Type = 3) THEN
- BEGIN
- WriteLn ('Drive is not present or non-removable');
- Halt
- END;
- IF D_Type = 2 THEN
- WriteLn ('Formatting 360K floppy in 1.2MB Drive');
- SetDASD(Drive, D_Type) { set the DASD type accordingly }
- END;
- Write ('Formatting... ');
- InitDiskBase; { set up the disk_base table }
- Format (Drive, FMT, Error); { lay down format tracks }
- BiosDiskBase := OldDiskBase; { restore the disk_base table }
- IF Error <> 0 THEN
- BEGIN
- WriteLn ('Error during format...');
- Halt
- END;
- Init_FAT; { initialize the FATtable }
- IF DoVerify THEN
- BEGIN { verify sectors }
- Write ('Verifying... ');
- Verify (Drive, FAT, Error)
- END;
- IF Error <> 0 THEN
- WriteLn ('Bad disk, format not verified...')
- ELSE
- BEGIN
- Write ('Writing BOOT/FAT/DIR... ');
- BIOS_WriteSectors(Drive, 1, 0, 0, 1, BR, Error); { write the boot record }
- Move (FAT[0], SB, 512); { write the FAT sectors }
- BIOS_WriteSectors (Drive, 2, 0, 0, 1, SB, Error);
- Move (FAT[512], SB, 512);
- BIOS_WriteSectors (Drive, 3, 0, 0, 1, SB, Error);
- Move (FAT[0], SB, 512);
- BIOS_WriteSectors (Drive, 4, 0, 0, 1, SB, Error);
- Move (FAT[512], SB, 512);
- BIOS_WriteSectors (Drive, 5, 0, 0, 1, SB, Error);
- Init_DIR; { write the root directory }
- BIOS_WriteSectors (Drive, 6, 0, 0, 1, SB, Error);
- BIOS_WriteSectors (Drive, 7, 0, 0, 1, SB, Error);
- BIOS_WriteSectors (Drive, 8, 0, 0, 1, SB, Error);
- BIOS_WriteSectors (Drive, 9, 0, 0, 1, SB, Error);
- BIOS_WriteSectors (Drive, 1, 0, 1, 1, SB, Error);
- BIOS_WriteSectors (Drive, 2, 0, 1, 1, SB, Error);
- BIOS_WriteSectors (Drive, 3, 0, 1, 1, SB, Error);
- B_Avail := 512.0 * (9.0 * T_Avail - 12.0); { calculate bytes available on disk }
- { 12 sectors are used by BOOT/FAT/DIR }
- WriteLn ('Format complete'#7);
- WriteLn ('Bytes Available: ', B_Avail:0:0)
- END;
- WriteLn;
- Write ('Format another? (Y/N) ');
- REPEAT
- Read (KBD, Ch);
- Ch := UpCase (Ch)
- UNTIL (Ch IN ['Y', 'N']);
- WriteLn (Ch);
- UNTIL Ch = 'N'
- END.
-